/* eslint-disable @typescript-eslint/no-explicit-any */
import styled from "@emotion/styled"
import { CSSProperties, ReactNode, useCallback, useEffect, useRef, useState } from "react"
import Css from "./css"

// 使用 const 導出 DragableContainer，使其可以被外部使用 styled 擴展
export const DragableContainer = styled.div`
    ${Css.Variables}
    ${Css.Normalize}
  ${Css.Dragging}
`

// 註冊的 CSS 變量類型
type RegisterCssVarType =
    | "--input-dragable-max-width"
    | "--input-dragable-background-color"
    | "--input-dragable-border-color"
    | "--input-dragable-border-width"
    | "--input-dragable-border-radius"
    | "--input-dragable-shadow"
    | "--input-dragable-z-index"

// 組件屬性類型，添加 HTMLDivElement 支持的所有屬性
type DragableProps = {
    children: ReactNode
    maxWidth?: CSSProperties["maxWidth"]
    backgroundColor?: CSSProperties["backgroundColor"]
    borderColor?: CSSProperties["borderColor"]
    borderWidth?: CSSProperties["borderWidth"]
    borderRadius?: CSSProperties["borderRadius"]
    boxShadow?: CSSProperties["boxShadow"]
    zIndex?: CSSProperties["zIndex"]
    style?: CSSProperties
    initialPosition?: { x: number; y: number }
    onDragStart?: () => void
    onDragEnd?: (position: { x: number; y: number }) => void
    onDragMove?: (position: { x: number; y: number }) => void
    className?: string
} & React.HTMLAttributes<HTMLDivElement>

function Dragable(props: DragableProps) {
    const {
        children,
        maxWidth,
        backgroundColor,
        borderColor,
        borderWidth,
        borderRadius,
        boxShadow,
        zIndex,
        style: customStyle,
        initialPosition,
        onDragStart,
        onDragEnd,
        onDragMove,
        className,
        // 解構其他 props
        ...restProps
    } = props

    // 設置內部狀態
    const [position, setPosition] = useState(initialPosition || { x: 0, y: 0 })
    const [isDragging, setIsDragging] = useState(false)
    const dragRef = useRef<HTMLDivElement>(null)
    const startPosRef = useRef({ x: 0, y: 0 })
    const offsetRef = useRef({ x: 0, y: 0 })

    // 合併樣式
    const style = {
        "--input-dragable-max-width": maxWidth,
        "--input-dragable-background-color": backgroundColor,
        "--input-dragable-border-color": borderColor,
        "--input-dragable-border-width": borderWidth,
        "--input-dragable-border-radius": borderRadius,
        "--input-dragable-shadow": boxShadow,
        "--input-dragable-z-index": zIndex,
        transform: `translate(${position.x}px, ${position.y}px)`,
        ...customStyle,
    } as any

    // 開始拖拽處理函數
    const handleMouseDown = useCallback(
        (e: React.MouseEvent | React.TouchEvent) => {
            e.stopPropagation()
            setIsDragging(true)
            if (onDragStart) onDragStart()

            // 獲取開始位置
            if ("touches" in e) {
                startPosRef.current = {
                    x: e.touches[0].clientX,
                    y: e.touches[0].clientY,
                }
            } else {
                startPosRef.current = {
                    x: e.clientX,
                    y: e.clientY,
                }
            }

            // 設置當前偏移量
            offsetRef.current = { ...position }
        },
        [position, onDragStart],
    )

    // 拖拽中處理函數
    const handleMouseMove = useCallback(
        (e: MouseEvent | TouchEvent) => {
            if (!isDragging) return

            let clientX: number
            let clientY: number

            if ("touches" in e) {
                clientX = e.touches[0].clientX
                clientY = e.touches[0].clientY
            } else {
                clientX = e.clientX
                clientY = e.clientY
            }

            const deltaX = clientX - startPosRef.current.x
            const deltaY = clientY - startPosRef.current.y

            const newPosition = {
                x: offsetRef.current.x + deltaX,
                y: offsetRef.current.y + deltaY,
            }

            setPosition(newPosition)
            if (onDragMove) onDragMove(newPosition)
        },
        [isDragging, onDragMove],
    )

    // 結束拖拽處理函數
    const handleMouseUp = useCallback(() => {
        if (isDragging) {
            setIsDragging(false)
            if (onDragEnd) onDragEnd(position)
        }
    }, [isDragging, onDragEnd, position])

    // 添加和移除事件監聽器
    useEffect(() => {
        if (isDragging) {
            window.addEventListener("mousemove", handleMouseMove)
            window.addEventListener("touchmove", handleMouseMove)
            window.addEventListener("mouseup", handleMouseUp)
            window.addEventListener("touchend", handleMouseUp)
        }

        return () => {
            window.removeEventListener("mousemove", handleMouseMove)
            window.removeEventListener("touchmove", handleMouseMove)
            window.removeEventListener("mouseup", handleMouseUp)
            window.removeEventListener("touchend", handleMouseUp)
        }
    }, [isDragging, handleMouseMove, handleMouseUp])

    return (
        <DragableContainer
            ref={dragRef}
            style={style}
            data-dragging={isDragging}
            onMouseDown={handleMouseDown}
            onTouchStart={handleMouseDown}
            className={className}
            // 傳遞其他 props
            {...restProps}
        >
            {children}
        </DragableContainer>
    )
}

// 讓 Dragable 可以被 styled 擴展
export default Dragable
